﻿Imports _7Wonders.Cartes

Public Class JoueurDebutant
    Inherits Joueur
    Implements Observateur

#Region "Variables"
    Private _carteJoueur As Carte
    Private _dct As New Dictionary(Of String, List(Of Carte))

    Private _dctRessourcesProduites As Dictionary(Of Carte.TypeRessouce, Integer)
    Private _dctRessourcesProduitesVoisinGauche As Dictionary(Of Carte.TypeRessouce, Integer)
    Private _dctRessourcesProduitesVoisinDroite As Dictionary(Of Carte.TypeRessouce, Integer)
#End Region

#Region "Constructeurs"

    Public Sub New(nomJoueur As String)
        MyBase.New(nomJoueur)
    End Sub

#End Region

    Public Overrides Sub Jouer()

        ' hardcoder
        ' déterminer les cartes pouvant être joué

        ' Déterminer le nombres de ressource produit par le joueur
        _dctRessourcesProduites = RessourcesProduites()
        _dctRessourcesProduitesVoisinGauche = RessourcesProduitesVoisinGauche()
        _dctRessourcesProduitesVoisinDroite = RessourcesProduitesVoisinDroite()

        Dim lstCarteJouable As New List(Of Carte)
        For Each carte As Carte In Main()
            If EstCarteJouable(carte) Then
                lstCarteJouable.Add(carte)
            End If
        Next

        If lstCarteJouable.Count > 0 Then
            Dim i As Integer = New Random().Next(lstCarteJouable.Count - 1)
            Plateau.CartesJoues.Add(lstCarteJouable(i))
            Console.WriteLine(String.Format("Joueur {0}: {1}", NomJoueur, lstCarteJouable(i)))
            JouerCarte(lstCarteJouable(i))

            Main.Remove(lstCarteJouable(i))
        Else
            ' todo selon la strategie du joueur employer, il devrait se débaraser d'une carte qui pourrais aidé son voisin!!!
            Dim i As Integer = New Random().Next(Main.Count - 1)
            EchangerCartePourPieceMonnaie(Main(i))
        End If
    End Sub

    Private Sub EchangerCartePourPieceMonnaie(carte As Carte)
        Console.WriteLine(String.Format("Joueur {0} vend la carte {1} pour 3 pièces de monnaie", NomJoueur, carte))
        Main.Remove(carte)
        Plateau.PiecesMonnaies += 3
    End Sub

    Public Function RessourcesProduites() As Dictionary(Of Carte.TypeRessouce, Integer)
        RessourcesProduites = RessoucesProduites(Plateau.CartesJoues)
        Return RessourcesProduites
    End Function

    Public Function RessourcesProduitesVoisinGauche() As Dictionary(Of Carte.TypeRessouce, Integer)
        RessourcesProduitesVoisinGauche = New Dictionary(Of Carte.TypeRessouce, Integer)
        If _dct.ContainsKey(ObtenirObservateurGauche.NomObservateur) Then
            RessourcesProduitesVoisinGauche = RessoucesProduites(_dct(ObtenirObservateurGauche.NomObservateur))
        End If

        Return RessourcesProduitesVoisinGauche
    End Function

    Public Function RessourcesProduitesVoisinDroite() As Dictionary(Of Carte.TypeRessouce, Integer)
        RessourcesProduitesVoisinDroite = New Dictionary(Of Carte.TypeRessouce, Integer)
        If _dct.ContainsKey(ObtenirObservateurDroite.NomObservateur) Then
            RessourcesProduitesVoisinDroite = RessoucesProduites(_dct(ObtenirObservateurDroite.NomObservateur))
        End If

        Return RessourcesProduitesVoisinDroite
    End Function

    Private Function ObtenirObservateurGauche() As Observateur
        Return Observateurs.FirstOrDefault(Function(x) x.Value = Sujet.EmplacementVoisin.Gauche).Key
    End Function

    Private Function ObtenirObservateurDroite() As Observateur
        Return Observateurs.FirstOrDefault(Function(x) x.Value = Sujet.EmplacementVoisin.Droite).Key
    End Function

    Private Function RessoucesProduites(cartes As List(Of Carte)) As Dictionary(Of Carte.TypeRessouce, Integer)
        RessoucesProduites = New Dictionary(Of Carte.TypeRessouce, Integer)

        For Each carte As Carte In cartes
            For Each choixTypeRessource In carte.Effet
                Dim query = choixTypeRessource.GroupBy(Function(x) x) _
                              .Select(Function(i) New With {.Effet = i.Key, .Count = i.Count()})

                If query.Count > 0 Then
                    If RessoucesProduites.ContainsKey(query(0).Effet) Then
                        RessoucesProduites.Item(query(0).Effet) += query(0).Count
                    Else
                        RessoucesProduites.Add(query(0).Effet, query(0).Count)
                    End If

                End If
            Next

        Next

        Return RessoucesProduites
    End Function


    ''' <summary>
    ''' Déterminer si les ressorce produite par LE Joueur suffisent à payé le coût de la carte
    ''' </summary>
    Private Function EstCarteJouableJoueur(couts As Dictionary(Of Carte.TypeRessouce, Integer)) As Dictionary(Of Boolean, Dictionary(Of Carte.TypeRessouce, Integer))
        EstCarteJouableJoueur = EstCarteJouable(couts, _dctRessourcesProduites)

        Return EstCarteJouableJoueur
    End Function

    ''' <summary>
    ''' Déterminer si les ressorce produite par LE VOISIN DE GAUCHE suffisent à payé le coût de la carte
    ''' </summary>
    Private Function EstCarteJouableVoisinGauche(couts As Dictionary(Of Carte.TypeRessouce, Integer)) As Dictionary(Of Boolean, Dictionary(Of Carte.TypeRessouce, Integer))
        EstCarteJouableVoisinGauche = EstCarteJouable(couts, _dctRessourcesProduitesVoisinGauche)

        Return EstCarteJouableVoisinGauche
    End Function

    ''' <summary>
    ''' Déterminer si les ressorce produite par LE VOISIN DE DROITE suffisent à payé le coût de la carte
    ''' </summary>
    Private Function EstCarteJouableVoisinDroit(couts As Dictionary(Of Carte.TypeRessouce, Integer)) As Dictionary(Of Boolean, Dictionary(Of Carte.TypeRessouce, Integer))
        EstCarteJouableVoisinDroit = EstCarteJouable(couts, _dctRessourcesProduitesVoisinDroite)

        Return EstCarteJouableVoisinDroit
    End Function

    ''' <summary>
    ''' Déterminer si les ressorce produite par un Joueur suffisent à payé le coût de la carte
    ''' </summary>
    Private Function EstCarteJouable(coutsCarte As Dictionary(Of Carte.TypeRessouce, Integer), ressourceProduite As Dictionary(Of Carte.TypeRessouce, Integer)) As Dictionary(Of Boolean, Dictionary(Of Carte.TypeRessouce, Integer))
        EstCarteJouable = New Dictionary(Of Boolean, Dictionary(Of Carte.TypeRessouce, Integer))

        For Each ressource As Carte.TypeRessouce In coutsCarte.Keys
            If ressourceProduite.ContainsKey(ressource) Then
                If coutsCarte(ressource) > ressourceProduite(ressource) Then
                    EstCarteJouable.Add(True, New Dictionary(Of Carte.TypeRessouce, Integer) From {{ressource, coutsCarte(ressource) - ressourceProduite(ressource)}})
                End If
            Else
                EstCarteJouable.Add(False, New Dictionary(Of Carte.TypeRessouce, Integer) From {{ressource, coutsCarte(ressource)}})
            End If
        Next

        If EstCarteJouable.Count = 0 Then
            EstCarteJouable.Add(True, New Dictionary(Of Carte.TypeRessouce, Integer))

        End If
        Return EstCarteJouable
    End Function

    Private Function EstCarteJouable(carte As Carte) As Boolean
        ' NOTE
        ' Cérer un objet de sorti contenant un liste de résultat
        ' boolean; comment; pieceMonnaie
        ' true; seul            ; 1 (banque)
        ' true; voisin gauche   ; 2 (donne a voisin gauche)
        ' true; voisin droite   ; 2 (donne a voisin droite)
        ' false; 

        Dim carteJouable As New CarteJouable

        EstCarteJouable = True

        ' Carte déja joué
        If Plateau.CartesJoues.Contains(carte) Then
            EstCarteJouable = False
        End If

        ' Déterminer le coût de la carte
        Dim dctCout As Dictionary(Of Carte.TypeRessouce, Integer) = DeterminerCoutCarte(carte)

        EstCarteJouable = EstCarteJouableJoueur(dctCout).ContainsKey(True) OrElse EstCarteJouableVoisinGauche(dctCout).ContainsKey(True) OrElse EstCarteJouableVoisinDroit(dctCout).ContainsKey(True)

        carteJouable.EstCarteJouable = EstCarteJouable

        '' Déterminer les nombres de ressource appartenant au joueur de gauche
        '' Déterminer les nombres de ressource appartenant au joueur de droite
        'DeterminerCoutCarte(carte)

        '' A le coût de construction requis
        'For Each ressourceRequis As Carte.TypeRessouce In carte.CoutRessource
        '    If ressourceRequis = carte.TypeRessouce.PieceMonaie Then
        '        If Me.Plateau.PiecesMonnaies >= 1 Then
        '            Me.Plateau.PiecesMonnaies -= 1
        '        Else
        '            EstCarteJouable = False
        '        End If
        '    Else
        '        Dim bln As Boolean = False
        '        For Each carte2 As Carte In Plateau.CartesJoues
        '            For Each a As List(Of Carte.TypeRessouce) In carte2.Effet
        '                If a.Contains(ressourceRequis) Then
        '                    bln = True
        '                    Exit For
        '                End If
        '            Next
        '        Next
        '        EstCarteJouable = bln
        '    End If
        'Next
        Return EstCarteJouable
    End Function

    Private Function DeterminerCoutCarte(carte As Carte) As Dictionary(Of Carte.TypeRessouce, Integer)

        DeterminerCoutCarte = RessoucesProduites(New List(Of Carte))

        For Each choixTypeRessource In carte.Effet
            Dim query = carte.CoutRessource.GroupBy(Function(x) x) _
                          .Select(Function(i) New With {.Cout = i.Key, .Count = i.Count()})

            If query IsNot Nothing Then
                For Each result In query
                    If DeterminerCoutCarte.ContainsKey(query(0).Cout) Then
                        DeterminerCoutCarte.Item(query(0).Cout) += query(0).Count
                    Else
                        DeterminerCoutCarte.Add(query(0).Cout, query(0).Count)
                    End If
                Next

            End If
        Next

        Return DeterminerCoutCarte
    End Function

    Private Sub AfficherCarte(carte As Carte)
        Dim colorDefault As System.ConsoleColor = Console.ForegroundColor

        Select Case carte.Couleur
            Case carte.TypeCouleur.Bleue
                Console.ForegroundColor = ConsoleColor.Blue

            Case carte.TypeCouleur.Grise
                Console.ForegroundColor = ConsoleColor.Gray

            Case carte.TypeCouleur.Jaune
                Console.ForegroundColor = ConsoleColor.Yellow

            Case carte.TypeCouleur.Marron
                Console.ForegroundColor = ConsoleColor.DarkYellow

            Case carte.TypeCouleur.Rouge
                Console.ForegroundColor = ConsoleColor.Red

            Case carte.TypeCouleur.Verte
                Console.ForegroundColor = ConsoleColor.DarkGreen

            Case carte.TypeCouleur.Violette
                Console.ForegroundColor = ConsoleColor.DarkBlue

            Case Else
                Console.ForegroundColor = colorDefault
        End Select

        Console.WriteLine(carte.ToString)
        Console.ForegroundColor = colorDefault
    End Sub

    Public Overrides Sub AfficherRessourcesProduites()
        Dim colorDefault As System.ConsoleColor = Console.ForegroundColor
        Console.WriteLine("--------------")
        Console.WriteLine(String.Format("Production du joueur: {0}", Me.NomJoueur))
        Console.WriteLine("--------------")

        For Each typeRessouce In Me.RessourcesProduites.Keys
            Console.WriteLine(String.Format("({0}) {1}", RessourcesProduites(typeRessouce), typeRessouce.ToString))
        Next
        Console.WriteLine()
    End Sub

    Public Overrides Sub AfficherMain()
        Dim colorDefault As System.ConsoleColor = Console.ForegroundColor
        Console.WriteLine("--------------")
        Console.WriteLine(String.Format("Main du joueur: {0}", Me.NomJoueur))
        Console.WriteLine("--------------")

        For Each carte In Main
            AfficherCarte(carte)
        Next
        Console.WriteLine()
    End Sub

    Public Overrides Sub AfficherJeu()
        Dim colorDefault As System.ConsoleColor = Console.ForegroundColor
        Console.WriteLine("--------------")
        Console.WriteLine(String.Format("Cartes jouées: {0}", Me.NomJoueur))
        Console.WriteLine("--------------")

        For Each carte In Plateau.CartesJoues
            AfficherCarte(carte)
        Next
        Console.WriteLine()
    End Sub

    Public Overrides Sub AfficherJeuxVoisins()
        For Each joueur As String In _dct.Keys
            Dim colorDefault As System.ConsoleColor = Console.ForegroundColor
            Console.WriteLine("--------------")
            Console.WriteLine(String.Format("{0} voit son voisin: {1}", Me.NomJoueur, joueur))
            Console.WriteLine("--------------")

            For Each carte In _dct(joueur)
                AfficherCarte(carte)
            Next
            Console.WriteLine()

        Next
    End Sub

    Public Overrides Sub AfficherRessourcesVoisinGauche()
        Dim colorDefault As System.ConsoleColor = Console.ForegroundColor
        Console.WriteLine("--------------")
        Console.WriteLine(String.Format("Production du voisin de gauche: {0}", ObtenirObservateurGauche.NomObservateur))
        Console.WriteLine("--------------")

        For Each typeRessouce In Me.RessourcesProduitesVoisinGauche.Keys
            Console.WriteLine(String.Format("({0}) {1}", RessourcesProduitesVoisinGauche(typeRessouce), typeRessouce.ToString))
        Next
        Console.WriteLine()
    End Sub

    Public Overrides Sub AfficherRessourcesVoisinDroite()
        Dim colorDefault As System.ConsoleColor = Console.ForegroundColor
        Console.WriteLine("--------------")
        Console.WriteLine(String.Format("Production du voisin de droite: {0}", ObtenirObservateurDroite.NomObservateur))
        Console.WriteLine("--------------")

        For Each typeRessouce In Me.RessourcesProduitesVoisinDroite.Keys
            Console.WriteLine(String.Format("({0}) {1}", RessourcesProduitesVoisinDroite(typeRessouce), typeRessouce.ToString))
        Next
        Console.WriteLine()
    End Sub

    Public Overrides Sub NotifierObservateur()
        For Each o As Observateur In MyBase.Observateurs.Keys
            'o.Actualiser(String.Format("Joueur {0} notify Joueur {1}. Carte joué: {2}", NomJoueur, o.NomObservateur, _carteJoueur))
            o.MAJVoisin(NomJoueur, _carteJoueur)
        Next
    End Sub

    Private Sub JouerCarte(carte As Carte)
        _carteJoueur = carte
        NotifierObservateur()
    End Sub

#Region "Implémentations de l'Observateur"
    Public Sub Actualiser(message As String) Implements Observateur.Actualiser
        Console.WriteLine(message)
    End Sub

    Private Sub MAJVoisin(nomJoueur As String, carte As Carte) Implements Observateur.MAJVoisin
        If Not _dct.Keys.Contains(nomJoueur) Then
            _dct.Add(nomJoueur, New List(Of Carte))
        End If
        _dct(nomJoueur).Add(carte)
    End Sub

    Public ReadOnly Property NomObservateur As String Implements Observateur.NomObservateur
        Get
            Return NomJoueur
        End Get
    End Property

#End Region
End Class
